--[[ Modified by Tronex 2020/3/26 Биндер объекта костра -------------------------------------------- name your campfires in SDK _campfire_ if you want them to be lit by NPCs --]] local k_rain = 0 local dist_cf = 2 --[meters] distance to interact with campfire campfires_all = {} function get_nearby_campfire (dist, result) local pos = db.actor:position() for id,binder in pairs(campfires_all) do if (binder and binder.campfire) then if (pos:distance_to_sqr(binder.object:position()) <= dist) then --printf("TRX found campfires = " .. binder.object:id()) if (result == true) then return binder.campfire elseif (result == false) then return binder.object else return true end end end end return false end function check_no_nearby_campfire() local nearby = get_nearby_campfire(2.5) return (not nearby) end function turn_off_campfires_by_smart_name(smart_name,use_rand) local smart_campfires = db.campfire_table_by_smart_names[smart_name] if smart_campfires ~= nil and not is_empty(smart_campfires) then for k,v in pairs (smart_campfires) do if (math.random(100) < 20) then -- shouldn't be needed with Open Xray because of DX11 lighting fix --if (v.object) then -- if (render_get_dx_level() == 655361) then -- v.object:disable_anomaly() -- end --end if (v.campfire and v.campfire:is_on()) then v.campfire:turn_off() end end end end end function rain_pass() local rain = level.rain_factor() if (rain ~= nil) and (rain > 0 and rain < 0.5) then return (math.random(1,2) == 1) elseif (rain > 0.5) then return (math.random(1,3) == 1) else return true end end function use_campfire(actor,zone,p) -- called from game_tutorials.xml local pos = db.actor:position() for id,binder in pairs(campfires_all) do if (binder and binder.campfire) then if (pos:distance_to_sqr(binder.object:position()) <= 2) then if (binder.campfire:is_on()) then campfire_go_off(binder.campfire) --binder.campfire:turn_off() else campfire_go_on(obj, cf) end end end end end function campfire_go_on(obj, cf) local cf = cf or get_nearby_campfire(dist_cf,true) if (not cf) then return end if (cf:is_on()) then return end if rain_pass() then if (k_rain < 1)then k_rain = k_rain + 1 actor_menu.set_msg(1, game.translate_string("st_camp_help"),3) end actor_effects.play_item_fx("matches_script") --local snd_obj = sound_object("interface\\inv_matches") --snd_obj:play(db.actor,0,sound_object.s2d) xr_sound.set_sound_play(AC_ID,"inv_matches") cf:turn_on() else actor_effects.play_item_fx("matches_script") actor_menu.set_msg(1, game.translate_string("st_fail"),3) end utils_item.discharge(obj) end function campfire_go_off(cf) local cf = cf or get_nearby_campfire(dist_cf,true) if cf and (cf:is_on()) then actor_effects.play_item_fx("matches_script") cf:turn_off() end end -------------------------------------------------------------------------------- -- Callbacks -------------------------------------------------------------------------------- local tutorial_ran = 0 -- because we don't want to conflict with other tutorials, we need to identify if we are running (ie. > 0) local function save_state(m_data) --utils_data.debug_write("bind_campfire:save_state") empty_table(m_data.campfire_states) for smart,t in pairs(db.campfire_table_by_smart_names) do for id,binder in pairs(t) do if (binder and binder.campfire) then if (binder.campfire:is_on()) then if not (m_data.campfire_states) then m_data.campfire_states = {} end m_data.campfire_states[id] = true end end end end end local function on_before_save_input(flags, typ, text) if (alife_storage_manager.get_state().enable_campfire_mode) and (level_weathers.valid_levels[level.name()]) and check_no_nearby_campfire() then local str = strformat(game.translate_string("st_ui_no_save_campfire"),text) actor_menu.set_msg(1, str,4) exec_console_cmd("main_menu off") flags.ret = true end end local function actor_on_update() if not (db.actor) then return end -- Don't show tutorial when actor weapon is active --if (db.actor:active_item()) then -- Don't show tutorial when actor is looking at an object local pos = db.actor:position() local obj = level.get_target_obj() if obj and (pos:distance_to_sqr(obj:position()) <= dist_cf + 2) then if (tutorial_ran > 0) then tutorial_ran = 0 if (game.has_active_tutorial()) then game.stop_tutorial() end end return end for id,binder in pairs(campfires_all) do if (binder and binder.campfire) then if (pos:distance_to_sqr(binder.object:position()) <= dist_cf) then if (not game.has_active_tutorial()) then tutorial_ran = id if (binder.campfire:is_on()) then --printf("tutorial_campfire_extinguish") game.start_tutorial("tutorial_campfire_extinguish") else --printf("tutorial_campfire_ignite") game.start_tutorial("tutorial_campfire_ignite") end end elseif (tutorial_ran == id) then tutorial_ran = 0 if (game.has_active_tutorial()) then game.stop_tutorial() end end end end end function on_game_start() local function on_game_load() if alife_storage_manager.get_state().enable_campfire_mode then RegisterScriptCallback("on_before_save_input",on_before_save_input) end end RegisterScriptCallback("on_game_load",on_game_load) RegisterScriptCallback("actor_on_update",actor_on_update) end -------------------------------------------------------------------------------- -- Class "campfire_binder" -------------------------------------------------------------------------------- function bind(obj) obj:bind_object(campfire_binder(obj)) end class "campfire_binder" (object_binder) function campfire_binder:__init(obj) super(obj) self.campfire = obj:get_campfire() if (USE_MARSHAL) then RegisterScriptCallback("save_state",save_state) end end function campfire_binder:reload(section) object_binder.reload(self, section) end function campfire_binder:reinit() object_binder.reinit(self) end function campfire_binder:net_spawn(se_abstract) if not object_binder.net_spawn(self, se_abstract) then return false end campfires_all[self.object:id()] = self local id = self.object:id() local m_data = alife_storage_manager.get_state() if (m_data and m_data.campfire_states and m_data.campfire_states[id]) then -- do not turn off campfire on game load m_data.campfire_states[id] = nil else if (self.campfire and self.campfire:is_on()) then self.campfire:turn_off() end --if (render_get_dx_level() == 655361) then -- self.object:disable_anomaly() --end end local smart_name = string.gsub(self.object:name(), "_campfire_%d*", "") if SIMBOARD.smarts_by_names[smart_name] then if db.campfire_table_by_smart_names[smart_name] == nil then db.campfire_table_by_smart_names[smart_name] = {} end db.campfire_table_by_smart_names[smart_name][id] = self end --[[ self.object:set_callback(callback.use_object, self.use_campfire, self) if (self.campfire) then if (self.campfire:is_on()) then self.object:set_tip_text("st_ignite_fire") else self.object:set_tip_text("st_extinguish_fire") end end --]] return true end function campfire_binder:net_destroy(se_abstract) local smart_name = string.gsub(self.object:name(), "_campfire_%d*", "") if SIMBOARD.smarts_by_names[smart_name] then if (db.campfire_table_by_smart_names[smart_name]) then db.campfire_table_by_smart_names[smart_name][self.object:id()] = nil end end --[[ self.object:set_callback(callback.use_object, nil) self.object:set_tip_text("") --]] object_binder.net_destroy(self) end function campfire_binder:update(delta) object_binder.update(self, delta) end --[[ function campfire_binder:use_campfire() if not (self.campfire) then return end if (self.campfire:is_on()) then self.campfire:turn_off() self.object:set_tip_text("st_ignite_fire") else self.campfire:turn_on() self.object:set_tip_text("st_extinguish_fire") end end --]] --[[ function turn_on_campfires_by_smart_name(smart_name,use_rand) local smart_campfires = db.campfire_table_by_smart_names[smart_name] if smart_campfires ~= nil and not is_empty(smart_campfires) then for k,v in pairs (smart_campfires) do if (v.object) then if (render_get_dx_level() == 655361) then v.object:enable_anomaly() end end if (v.campfire and not v.campfire:is_on()) then v.campfire:turn_on() end end end end --]]